package commons.utils.primitive_geom;

import commons.spatialindex.I_SpatialIndexable;

public class Rect_d implements I_SpatialIndexable
{
	public double xMin;
	public double yMin;
	public double xMax;
	public double yMax;
	
	public Rect_d(){
		xMin = 0;
		yMin = 0;
		xMax = 0;
		yMax = 0;
	}
	public Rect_d(Rect_d r){
		xMin = r.xMin;
		yMin = r.yMin;
		xMax = r.xMax;
		yMax = r.yMax;
	}
	public Rect_d(double xMin, double yMin, double xMax, double yMax) {
		assert(xMin<=xMax && yMin<=yMax);
		this.xMin = xMin;
		this.yMin = yMin;
		this.xMax = xMax;
		this.yMax = yMax;
	}
	public Rect_d(Point_d pt) {
		xMin = pt.x;
		yMin = pt.y;
		xMax = pt.x;
		yMax = pt.y;
	}
	public Rect_d(Point_d pt1, Point_d pt2) {
		xMin = Math.min(pt1.x, pt2.x);
		yMin = Math.min(pt1.y, pt2.y);
		xMax = Math.max(pt1.x, pt2.x);
		yMax = Math.max(pt1.y, pt2.y);
	}
	public Rect_d(Segment_d seg) {
		this(seg.pt1, seg.pt2);
	}
	public Rect_d(double x, double y, double lgCote) {
		assert(lgCote>=0);
		xMin = x - lgCote / 2;
		yMin = y - lgCote / 2;
	    xMax = x + lgCote / 2;
	    yMax = y + lgCote / 2;
	}
	public Rect_d(Point_d ptCenter, double lgCote) {
		assert(lgCote>=0);
		xMin = ptCenter.x - lgCote / 2;
		yMin = ptCenter.y - lgCote / 2;
	    xMax = ptCenter.x + lgCote / 2;
	    yMax = ptCenter.y + lgCote / 2;
	}
	public Rect_d(Point_d ptCenter, double largeur, double hauteur) {
		assert(largeur>=0 && hauteur>=0);
		xMin = ptCenter.x - largeur / 2;
		yMin = ptCenter.y - hauteur / 2;
	    xMax = ptCenter.x + largeur / 2;
	    yMax = ptCenter.y + hauteur / 2;
	}   

	public void setCoord(double xMin, double yMin, double xMax, double yMax) {
		assert(xMin<=xMax && yMin<=yMax);
		this.xMin = xMin;
		this.yMin = yMin;
		this.xMax = xMax;
		this.yMax = yMax;
	}

	public void setCoord(double xCenter, double yCenter, double lgCote) {
		assert(lgCote>=0);
		this.xMin = xCenter - lgCote / 2;
		this.yMin = yCenter - lgCote / 2;
		this.xMax = xCenter + lgCote / 2;
		this.yMax = yCenter + lgCote / 2;
	}

	public void setCoordFrom(Point_d pt) {
		xMin = pt.x;
		yMin = pt.y;
		xMax = pt.x;
		yMax = pt.y;
	}
	public void setCoordFrom(Rect_d r) {
		xMin = r.xMin;
		yMin = r.yMin;
		xMax = r.xMax;
		yMax = r.yMax;
	}
	public void setCoordFrom(Point_d ptCenter, double largeur, double hauteur) {
		assert(largeur>=0 && hauteur>=0);
		xMin = ptCenter.x - largeur / 2;
		yMin = ptCenter.y - hauteur / 2;
	    xMax = ptCenter.x + largeur / 2;
	    yMax = ptCenter.y + hauteur / 2;
	}
	
	public Rect_d getCopy()	{
		return new Rect_d(xMin, yMin, xMax, yMax);
	}
	
	public double getWidth(){
		return xMax-xMin;
	}
	
	public double getHeight(){
		return yMax-yMin;
	}

	public double getSurface() {
		return (xMax-xMin) * (yMax-yMin);
	}
	
	public Point_d getCenter() {
		return new Point_d ( (xMax+xMin) / 2 , (yMax+yMin) / 2 );
	}

	public boolean isPoint() {
		return xMin==xMax && yMin==yMax;
	}

	public Point_d getPt (int numPt) {
		assert (numPt>=1 && numPt<=4);
		if (numPt==1)
			return new Point_d(xMin, yMin);
		else if (numPt==2)
			return new Point_d(xMax, yMin);
		else if (numPt==3)
			return new Point_d(xMax, yMax);
		else if (numPt==4)
			return new Point_d(xMin, yMax);
		else return null;
	}

	public void decale (double dx, double dy) {
		xMin += dx;
		xMax += dx;
		yMin += dy;
		yMax += dy;
	}
	
	public Rect_d expand (double dx, double dy) {
		// on s'assure que le rect ne va pas se "retourner sur lui-même"
		// car sinon, on aura plus xMax >= xMin etc.
		assert(dx>=-(xMax-xMin)/2 && dy>=-(yMax-yMin)/2);
	    xMin = xMin - dx;
	    xMax = xMax + dx;
	    yMin = yMin - dy;
	    yMax = yMax + dy;
		return this;
	}
	public Rect_d expand (double facteur) {
		expand(getWidth() * (facteur-1) / 2, getHeight() * (facteur-1) / 2);
		return this;
	}
	
	public void extendToPoint (Point_d pt) {
		xMin = Math.min(xMin, pt.x);
	    yMin = Math.min(yMin, pt.y);
	    xMax = Math.max(xMax, pt.x);
	    yMax = Math.max(yMax, pt.y);
	}
	public void extendToSeg (Segment_d seg) {
		
		double segMinX, segMaxX, segMinY, segMaxY;
		
		if (seg.pt1.x < seg.pt2.x) {
			segMinX = seg.pt1.x;
			segMaxX = seg.pt2.x;
		} else {
			segMinX = seg.pt2.x;
			segMaxX = seg.pt1.x;
		}
		if (seg.pt1.y < seg.pt2.y) {
			segMinY = seg.pt1.y;
			segMaxY = seg.pt2.y;
		} else {
			segMinY = seg.pt2.y;
			segMaxY = seg.pt1.y;
		}
			
		xMin = Math.min(xMin, segMinX);
	    yMin = Math.min(yMin, segMinY);
	    xMax = Math.max(xMax, segMaxX);
	    yMax = Math.max(yMax, segMaxY);
	}
	public void extendToRect (Rect_d r) {
		xMin = Math.min(xMin, r.xMin);
	    yMin = Math.min(yMin, r.yMin);
	    xMax = Math.max(xMax, r.xMax);
	    yMax = Math.max(yMax, r.yMax);
	}

	public boolean contientPt_larg (Point_d pt) {
		return (pt.x>=xMin && pt.x<=xMax && pt.y>=yMin && pt.y<=yMax);
	}
	public boolean contientPt_strict (Point_d pt) {
		return (pt.x>xMin && pt.x<xMax && pt.y>yMin && pt.y<yMax);
	}
	public boolean contientSeg_larg (Segment_d seg) {
		return contientPt_larg(seg.pt1) && contientPt_larg(seg.pt2);
	}
	public boolean contientSeg_strict (Segment_d seg) {
		return contientPt_strict(seg.pt1) && contientPt_strict(seg.pt2);
	}

	@Override
	public String toString () {
		return "" + xMin + " , " + yMin + " , " + xMax + " , " + yMax;
	}

	public double getXMin() {
		return xMin;
	}

	public double getXMax() {
		return xMax;
	}

	public double getYMin() {
		return yMin;
	}

	public double getYMax() {
		return yMax;
	}

	public Rect_d getRectEmprise() {return this;}

	public boolean equals(Rect_d rect) {
		return this.xMin==rect.xMin && this.xMax==rect.xMax && this.yMin==rect.yMin && this.yMax==rect.yMax;
	}
}
